//Random Game Engine
//Copyright (C) 2013  Nikolay Dionisov

//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.



#ifndef __MANAGER_INTERFACES__H_INCLUDED__
#define __MANAGER_INTERFACES__H_INCLUDED__
#include <memory>
#include <map>
#include "..\Utilities\ThreadSafePrimitives.h"
namespace re
{
	namespace core
	{
		//*********************************************************************************
		//State Manager Interfaces
		//*********************************************************************************
		typedef unsigned int MessageType;
		class StateMessage
		{
		public:
			StateMessage() {}
			virtual ~StateMessage() {}

			virtual StateMessage* Duplicate() = 0;
			virtual MessageType GetMessageType() = 0;
		};
		typedef std::shared_ptr<StateMessage> StateMessagePtr;
		class StateManager;


			class IStateListenerCallback
		{
		public:
			IStateListenerCallback() {}
			virtual ~IStateListenerCallback();

			virtual void Call(void* owner, StateMessagePtr msg) = 0;
		};
		template<class T, class Y>
		class StateListenerCallback
		{
		public:
			typedef void (T::*clb_pointer)(Y* data);
			StateListenerCallback(clb_pointer callback) 
			{
				callback_ = callback;
			}
			virtual ~StateListenerCallback() {}

			void Call(void* owner, StateMessagePtr msg)
			{
				Y* param = dynamic_cast<Y*>(msg.get());
				(dynamic_cast<Y*>(owner)->*callback_)(param);
			}
		private:
			clb_pointer callback_;
		};
		typedef std::shared_ptr<IStateListenerCallback> StateListenerCallbackPtr;
		typedef std::map<MessageType, StateListenerCallbackPtr> StateListenerCallbackMap;



		class IStateListener
		{
		public:
			IStateListener() {}
			virtual ~IStateListener() {}
			friend class StateManager;

			virtual void SetMsgCallback(MessageType type, StateListenerCallbackPtr callback) = 0;
			virtual void RemoveMsgCallback(MessageType type) = 0;
			virtual void Update() = 0;
		protected:
			virtual void HandleMessage(StateMessagePtr msg) = 0;
		};
		typedef std::shared_ptr<IStateListener> StateListenerPtr;
		class IStateManager
		{
		public:
			IStateManager() {}
			virtual ~IStateManager() {}

			virtual void RegisterMsgType(MessageType type) = 0;
			virtual void UnregisterMsgType(MessageType type) = 0;
			virtual void RegisterListener(StateListenerPtr listener, MessageType type) = 0;
			virtual void UnregisterListener(StateListenerPtr listener) = 0;
			virtual StateListenerPtr CreateStateListener() = 0;

			virtual void SendMsg(StateMessagePtr msg) = 0;
		};


		//*********************************************************************************
		//Task Manager Interfaces
		//*********************************************************************************
		class Task;class ISystem;
		class Work
		{
		public:
			Work() { }
			virtual ~Work() {}
			virtual void DoWork() = 0;
		};
		typedef std::shared_ptr<Work> WorkPtr;
		typedef unsigned short TaskId;
		typedef unsigned char SessionId;

		class ITaskManager
		{
		public:
			ITaskManager() {}
			virtual ~ITaskManager() {}

			virtual TaskId AddTask(WorkPtr work, const SessionId session) = 0;
			virtual void SetParent(const SessionId session, const TaskId parent, const TaskId child) = 0;
			virtual void SetDependency(const SessionId session, const TaskId to_exec_first, const TaskId to_exec_second) = 0;
			//Begin the builing of a task tree.
			//Require session mutex. WARNING StartSession MUST be ended with FinishSession()
			virtual SessionId StartSession() = 0;
			//Finish the session(send the session to the exec queue)
			//Require task and session mutexes(should be calles ONLY once per update)
			virtual void FinishSession(SessionId id) = 0;

			virtual bool IsCompleted(TaskId id) = 0;

			//If there is task -> Do. else wait until there is a task .
			virtual void WaitDoTask() = 0;
			//If there is task -> Do. else quit.
			virtual bool TryDoTask() = 0;
		};
	}
}

#endif